package c0907m.group2.aitsm.util;


import javax.swing.*;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Author: LongDH
 * Date: 4/24/11
 * Time: 11:04 PM
 * <p/>
 * Useful constants and methods for the project.
 */
public abstract class Helper {
    public static final Properties PROPS = new Properties();

    /**
     * Initialize the logging system. Always call this method before creating any logger.
     */
    public static void initSystem() {
        File dir = new File("log");
        if (!dir.exists()) dir.mkdir();

        Logger root = Logger.getLogger("c0907m.group2.aitsm");
        root.setUseParentHandlers(false);
        try {
            Handler handler = new ConsoleHandler();
            handler.setFormatter(new SimpleLogFormatter());
            root.addHandler(handler);

            handler = new AutoDateFileHandler("'log" + Settings.SEPARATOR + "'MM-dd-yyyy'.log'", true, Calendar.DATE);
            handler.setFormatter(new SimpleLogFormatter());
            root.addHandler(handler);
        } catch (Exception e) {
            root.warning("Init log error: " + e.getMessage());
        }

        try {
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        } catch (ClassNotFoundException e) {
            root.severe(e.toString());
            System.exit(1);
        }

        try {
            PROPS.load(new FileInputStream(new File(Settings.CONFIG)));
        } catch (IOException e) {
            root.severe("Error load config: " + e.getMessage());
        }
    }

    /**
     * Connect to database.
     *
     * @return the database connection.
     * @throws SQLException if a database access error occurs
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(new StringBuilder()
                .append("jdbc:sqlserver://")
                .append(PROPS.getProperty("host")).append(":").append(PROPS.getProperty("port"))
                .append(";databaseName=").append(PROPS.getProperty("database")).toString(),
                PROPS.getProperty("user"),
                PROPS.getProperty("password"));
    }

	/**
	 * Encode a string by MD5 algorithm.
	 * @param toEncode string to be encoded.
	 * @return encoded string.
	 */
	public static String MD5(String toEncode) {
		MessageDigest algorithm = null;
		try {
			algorithm = MessageDigest.getInstance("MD5");
			algorithm.update(toEncode.getBytes());
			StringBuilder sb = new StringBuilder();
			for (byte b : algorithm.digest()) {
				sb.append(Integer.toHexString(0xFF & b));
			}
			return sb.toString();
		} catch (NoSuchAlgorithmException e) {
			Logger.getLogger(Helper.class.getName()).warning("Unable to MD5: " + e.getMessage());
		}
		return null;
	}

    /**
     * Formats current date into a date/time string.
     *
     * @param pattern the pattern describing the date and time format.
     * @return the formatted time string, null if unable to format.
     */
    public static String fromCurrentDate(String pattern) {
        return fromDate(new Date(), pattern);
    }

    /**
     * Formats current date into a date/time string with default pattern: MM-dd-yyyy.
     *
     * @return the formatted time string, null if unable to format.
     */
    public static String fromCurrentDate() {
        return fromCurrentDate(null);
    }

    /**
     * Formats a Date into a date string.
     *
     * @param date    the time value to be formatted into a time string.
     * @param pattern the pattern describing the date and time format.
     * @return the formatted time string, null if unable to format.
     */
    public static String fromDate(Date date, String pattern) {
        try {
            return (pattern == null || pattern.trim().length() == 0) ?
                    new SimpleDateFormat("MM-dd-yyyy").format(date) :
                    new SimpleDateFormat(pattern).format(date);
        } catch (Exception e) {
            Logger.getLogger(Helper.class.getName()).warning("Unable to format date: " + e.getMessage());
            return null;
        }
    }

    /**
     * Formats a Date into a date time string with default pattern: MM-dd-yyyy HH:mm.
     *
     * @param date the time value to be formatted into a time string.
     * @return the formatted time string, null if unable to format.
     */
    public static String fromDateTime(Date date) {
        return fromDate(date, "MM-dd-yyyy HH:mm");
    }

    /**
     * Formats a Date into a date string with default pattern: MM-dd-yyyy.
     *
     * @param date the time value to be formatted into a time string.
     * @return the formatted time string, null if unable to format.
     */
    public static String fromDate(Date date) {
        return fromDate(date, null);
    }

    /**
     * Convert a date string into Date object for importing to database.
     *
     * @param date    the date to convert.
     * @param pattern the pattern describing the date and time format.
     * @return A Date parsed from the string, null if unparseable.
     */
    public static Date toDate(String date, String pattern) {
        try {
            return (pattern == null || pattern.trim().length() == 0) ?
                    new SimpleDateFormat("MM-dd-yyyy").parse(date) :
                    new SimpleDateFormat(pattern).parse(date);
        } catch (Exception e) {
            Logger.getLogger(Helper.class.getName()).warning("Unable to format date: " + e.getMessage());
            return null;
        }
    }

    /**
     * Convert a date time string into Date object for importing to database with default pattern: MM-dd-yyyy HH:mm.
     *
     * @param date the date to convert.
     * @return A Date parsed from the string, null if unparseable.
     */
    public static Date toDateTime(String date) {
        return toDate(date, "MM-dd-yyyy HH:mm");
    }

    /**
     * Convert a date string into Date object for importing to database with default pattern: MM-dd-yyyy.
     *
     * @param date the date to convert.
     * @return A Date parsed from the string, null if unparseable.
     */
    public static Date toDate(String date) {
        return toDate(date, null);
    }

    /**
     * Compute the amount charged by this fine.
     *
     * @param present number of days attended.
     * @param total   total number of days.
     * @param rate    charge rate.
     * @return the calculated result. Zero for not being charged.
     */
    public static double calculateLevi(int present, int total, double rate) {
        double percent = (double) present / total * 100f;
        int minRate = Integer.parseInt(Helper.PROPS.getProperty("minRate"));
        int maxRate = Integer.parseInt(Helper.PROPS.getProperty("maxRate"));
        return (percent >= minRate && percent <= maxRate) ? (total - present) * rate : 0;
    }

    /**
     * Show a Swing component if it's hidden, and contrast.
     *
     * @param c the component to be toggled.
     */
    public static void toggle(Component c) {
        c.setVisible(!c.isVisible());
    }

    /**
     * Set application's Look and Feel to Window.
     */
    public static void setLookAndFeel(String lnf) {
        try {
            UIManager.setLookAndFeel(lnf);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Method to add a JComboBox into a table cell
     *
     * @param table    target table
     * @param cb       JComboBox to add
     * @param colIndex index of target column
     * @return a cell's editor
     */
    public static DefaultCellEditor addComboBoxToTable(JTable table, JComboBox cb, int colIndex) {
        TableColumn col = table.getColumnModel().getColumn(colIndex);
        col.setCellEditor(new DefaultCellEditor(cb));
        return (DefaultCellEditor) col.getCellEditor();
    }

    /**
     * Parse a string represent a day or month into right pattern (mm, MM)
     *
     * @param toParse string to parse
     * @return parsed string
     */
    public static String parsePattern(String toParse) {
        return (Integer.parseInt(toParse) < 10) ? "0" + toParse : toParse;
    }

    /**
     * Save all configurations.
     */
    public static synchronized void saveSettings() {
        try {
            PROPS.store(new FileOutputStream(new File(Settings.CONFIG)), null);
        } catch (IOException e) {
            Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, e);
        }
    }
}
